﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using IronCow.UnitTests.Mock;
using NUnit.Framework.SyntaxHelpers;

namespace IronCow.UnitTests
{
    [TestFixture]
    public class TestTaskLists
    {
        private MockRtm Rtm;

        [SetUp]
        public void SetUp()
        {
            Rtm = new MockRtm();
        }

        [TearDown]
        public void TearDown()
        {
            Rtm.EnsureAllResponsesUsed();
        }

        [Test]
        public void TestGetTaskLists()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(100653, "Inbox", TaskListFlags.Locked),
                    new MockListResponsePart(387549, "High Priority", TaskListFlags.Smart, "(priority:1)"),
                    new MockListResponsePart(387546, "New List"),
                    new MockListResponsePart(100654, "Personal"),
                    new MockListResponsePart(100655, "Study"),
                    new MockListResponsePart(100656, "Work"),
                    new MockListResponsePart(100657, "Sent", TaskListFlags.Locked)
                });

            Assert.AreEqual(7, Rtm.TaskLists.Count);

            Assert.AreEqual("Inbox", Rtm.TaskLists[0].Name);
            Assert.IsTrue(Rtm.TaskLists[0].GetFlag(TaskListFlags.Locked));
            Assert.AreEqual("High Priority", Rtm.TaskLists[1].Name);
            Assert.AreEqual("(priority:1)", Rtm.TaskLists[1].Filter);
            Assert.IsTrue(Rtm.TaskLists[1].GetFlag(TaskListFlags.Smart));
            Assert.AreEqual("New List", Rtm.TaskLists[2].Name);
            Assert.AreEqual("Personal", Rtm.TaskLists[3].Name);
            Assert.AreEqual("Study", Rtm.TaskLists[4].Name);
            Assert.AreEqual("Work", Rtm.TaskLists[5].Name);
            Assert.AreEqual("Sent", Rtm.TaskLists[6].Name);
            Assert.IsTrue(Rtm.TaskLists[6].GetFlag(TaskListFlags.Locked));
        }

        [Test]
        public void TestAddTaskList()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(100653, "Inbox", TaskListFlags.Locked),
                    new MockListResponsePart(387549, "High Priority", TaskListFlags.Smart, "(priority:1)"),
                    new MockListResponsePart(387546, "New List"),
                    new MockListResponsePart(100654, "Personal"),
                    new MockListResponsePart(100655, "Study"),
                    new MockListResponsePart(100656, "Work"),
                    new MockListResponsePart(100657, "Sent", TaskListFlags.Locked)
                });
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.lists.add", new MockListResponsePart(987654321, "Test List"));

            Assert.AreEqual(7, Rtm.TaskLists.Count);
            
            TaskList list = new TaskList();
            list.Name = "Test List";
            Assert.IsFalse(list.IsSynced);
            Rtm.TaskLists.Add(list);
            Assert.IsTrue(list.IsSynced);
            Assert.AreEqual("Test List", list.Name);
        }

        [Test]
        public void TestRemoveTaskList()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(100653, "Inbox", TaskListFlags.Locked),
                    new MockListResponsePart(387549, "High Priority", TaskListFlags.Smart, "(priority:1)"),
                    new MockListResponsePart(387546, "New List"),
                    new MockListResponsePart(100654, "Personal"),
                    new MockListResponsePart(100655, "Study"),
                    new MockListResponsePart(100656, "Work"),
                    new MockListResponsePart(100657, "Sent", TaskListFlags.Locked)
                });
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.lists.delete", new MockListResponsePart(387546, "New List (deleted)", TaskListFlags.Deleted));

            Assert.AreEqual(7, Rtm.TaskLists.Count);
            TaskList list = Rtm.TaskLists[2];
            Assert.AreEqual("New List", list.Name);
            Rtm.TaskLists.Remove(list);
            Assert.AreEqual(6, Rtm.TaskLists.Count);
            Assert.AreEqual("New List (deleted)", list.Name);
        }

        [Test]
        public void TestSetTaskListName()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(100653, "Inbox", TaskListFlags.Locked),
                    new MockListResponsePart(387549, "High Priority", TaskListFlags.Smart, "(priority:1)"),
                    new MockListResponsePart(387546, "New List"),
                    new MockListResponsePart(100654, "Personal"),
                    new MockListResponsePart(100655, "Study"),
                    new MockListResponsePart(100656, "Work"),
                    new MockListResponsePart(100657, "Sent", TaskListFlags.Locked)
                });
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.lists.setName", new MockListResponsePart(387546, "New List (renamed)"));

            TaskList list = Rtm.TaskLists[2];
            Assert.AreEqual("New List", list.Name);
            list.Name = "New List (renamed)";
            Assert.AreEqual("New List (renamed)", list.Name);
        }

        [Test]
        public void TestArchiveAndUnarchiveTaskList()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(100653, "Inbox", TaskListFlags.Locked),
                    new MockListResponsePart(387549, "High Priority", TaskListFlags.Smart, "(priority:1)"),
                    new MockListResponsePart(387546, "New List"),
                    new MockListResponsePart(100654, "Personal"),
                    new MockListResponsePart(100655, "Study"),
                    new MockListResponsePart(100656, "Work"),
                    new MockListResponsePart(100657, "Sent", TaskListFlags.Locked)
                });
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.lists.archive", new MockListResponsePart(387546, "New List", TaskListFlags.Archived));
            Rtm.AddSuccessResponse("rtm.lists.unarchive", new MockListResponsePart(387546, "New List", TaskListFlags.None));

            TaskList list = Rtm.TaskLists[2];
            Assert.IsFalse(list.GetFlag(TaskListFlags.Archived));
            list.Archive();
            Assert.IsTrue(list.GetFlag(TaskListFlags.Archived));
            list.Unarchive();
            Assert.IsFalse(list.GetFlag(TaskListFlags.Archived));
        }

        [Test]
        public void TestListsPopulatedOnSearch()
        {
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) }
                    },
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(1, "First list"),
                    new MockListResponsePart(2, "Second list"),
                    new MockListResponsePart(3, "Third list")
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) },
                        new MockTaskSeriesResponsePart(12, "Get monkey wrench") { new MockTaskResponsePart(12) },
                        new MockTaskSeriesResponsePart(13, "Get collar") { new MockTaskResponsePart(13) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) },
                        new MockTaskSeriesResponsePart(22, "Take trash out"){ new MockTaskResponsePart(22) }
                    }
                });

            Task[] tasks = Rtm.GetTasks(null, "Buy");
            Assert.IsNotNull(tasks);
            Assert.That(tasks, Has.Length(2));
            Assert.That(tasks[0].Id, Is.EqualTo("11"));
            Assert.That(tasks[1].Id, Is.EqualTo("21"));
            Assert.That(tasks[0].Parent, Is.SameAs(Rtm.TaskLists.GetById("1")));
            Assert.That(tasks[1].Parent, Is.SameAs(Rtm.TaskLists.GetById("2")));
        }

        [Test]
        public void TestSmartListTasksBelongToNonSmartLists()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(1, "First list"),
                    new MockListResponsePart(2, "Other list"),
                    new MockListResponsePart(3, "Smart list!!", TaskListFlags.Smart, "Buy")
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) }
                    },
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) },
                        new MockTaskSeriesResponsePart(12, "Get monkey wrench") { new MockTaskResponsePart(12) },
                        new MockTaskSeriesResponsePart(13, "Get collar") { new MockTaskResponsePart(13) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) },
                        new MockTaskSeriesResponsePart(22, "Take trash out"){ new MockTaskResponsePart(22) }
                    }
                });

            TaskList smartList = Rtm.TaskLists[2];
            Assert.AreEqual("3", smartList.Id);
            Assert.AreEqual("Smart list!!", smartList.Name);
            Assert.AreEqual("Buy", smartList.Filter);
            Assert.IsTrue(smartList.GetFlag(TaskListFlags.Smart));
            smartList.IsFrozen = true; // Freeze the smart list for convenience.

            Assert.That(smartList.Tasks, Has.Count(2));
            
            Task task0 = smartList.Tasks[0];
            Assert.IsNotNull(task0);
            Assert.AreSame(task0.Parent, Rtm.TaskLists[0]);

            Task task1 = smartList.Tasks[1];
            Assert.IsNotNull(task1);
            Assert.AreSame(task1.Parent, Rtm.TaskLists[1]);
        }

        [Test]
        public void TestSmartListAlwaysSyncOnAccess()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(1, "First list"),
                    new MockListResponsePart(2, "Other list"),
                    new MockListResponsePart(3, "Smart list!!", TaskListFlags.Smart, "Buy")
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) }
                    },
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) },
                        new MockTaskSeriesResponsePart(12, "Get monkey wrench") { new MockTaskResponsePart(12) },
                        new MockTaskSeriesResponsePart(13, "Get collar") { new MockTaskResponsePart(13) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) },
                        new MockTaskSeriesResponsePart(22, "Take trash out"){ new MockTaskResponsePart(22) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) }
                    },
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Buy bananas") { new MockTaskResponsePart(11) }
                    },
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) }
                    }
                });
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.tasks.setName",
                new MockTaskListResponsePart(1)
                {
                    new MockTaskSeriesResponsePart(11, "Get bananas") { new MockTaskResponsePart(11) }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(2)
                    {
                        new MockTaskSeriesResponsePart(21, "Buy milk"){ new MockTaskResponsePart(21) }
                    }
                });

            TaskList smartList = Rtm.TaskLists[2];
            Assert.AreEqual("3", smartList.Id);
            Assert.AreEqual("Smart list!!", smartList.Name);
            Assert.AreEqual("Buy", smartList.Filter);
            Assert.IsTrue(smartList.GetFlag(TaskListFlags.Smart));

            Assert.That(smartList.Tasks, Has.Count(2));
            Assert.That(smartList.Tasks, Has.Count(2));
            Task buyBananasTask = smartList.Tasks[0];
            Assert.AreEqual("11", buyBananasTask.Id);
            Assert.AreEqual("Buy bananas", buyBananasTask.Name);
            buyBananasTask.Name = "Get bananas";

            Assert.That(smartList.Tasks, Has.Count(1));
        }

        [Test]
        public void AddTaskToCompatibleSmartList()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(1, "Inbox"),
                    new MockListResponsePart(2, "Task for home", TaskListFlags.Smart, "tag:@home")
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(12, "Clean basement", DateTime.Now, "", "@home") { new MockTaskResponsePart(12) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Call Omar") { new MockTaskResponsePart(11) },
                        new MockTaskSeriesResponsePart(12, "Clean basement", DateTime.Now, "", "@home") { new MockTaskResponsePart(12) },
                        new MockTaskSeriesResponsePart(13, "Buy milk") { new MockTaskResponsePart(13) }
                    }
                });
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.tasks.add",
                new MockTaskListResponsePart(1)
                {
                    new MockTaskSeriesResponsePart(14, "Sort socks", DateTime.Now, "", "@home") { new MockTaskResponsePart(14) }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(12, "Clean basement", DateTime.Now, "", "@home") { new MockTaskResponsePart(12) },
                        new MockTaskSeriesResponsePart(14, "Sort socks", DateTime.Now, "", "@home") { new MockTaskResponsePart(14) }
                    }
                });

            TaskList smartList = Rtm.TaskLists[1];
            Assert.That(smartList.Tasks, Has.Count(1));

            Task newTask = new Task("Sort socks");
            smartList.AddTask(newTask);

            Assert.That(smartList.Tasks, Has.Count(2));
            smartList.IsFrozen = true;
            Assert.AreSame(newTask, smartList.Tasks[1]);
            Assert.AreSame(Rtm.TaskLists[0], newTask.Parent);
        }

        [Test]
        public void AddTaskToIncompatibleSmartList()
        {
            Rtm.AddSuccessResponse("rtm.lists.getList",
                new MockListsResponsePart()
                {
                    new MockListResponsePart(1, "Inbox"),
                    new MockListResponsePart(2, "Task due soon", TaskListFlags.Smart, "dueBefore:\"3 days\"")
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(12, "Clean basement", DateTime.Now)
                        {
                            new MockTaskResponsePart(12, DateTime.Now, TaskPriority.None, DateTime.Today.AddDays(2))
                        }
                    }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(11, "Call Omar") { new MockTaskResponsePart(11) },
                        new MockTaskSeriesResponsePart(12, "Clean basement", DateTime.Now)
                        {
                            new MockTaskResponsePart(12, DateTime.Now, TaskPriority.None, DateTime.Today.AddDays(2))
                        },
                        new MockTaskSeriesResponsePart(13, "Buy milk") { new MockTaskResponsePart(13) }
                    }
                });
            Rtm.AddSuccessResponse("rtm.settings.getList", new MockUserSettingsResponsePart());
            Rtm.AddTimelineResponse();
            Rtm.AddSuccessResponse("rtm.tasks.add",
                new MockTaskListResponsePart(1)
                {
                    new MockTaskSeriesResponsePart(14, "Sort socks") { new MockTaskResponsePart(14) }
                });
            Rtm.AddSuccessResponse("rtm.tasks.getList",
                new MockTasksResponsePart()
                {
                    new MockTaskListResponsePart(1)
                    {
                        new MockTaskSeriesResponsePart(12, "Clean basement", DateTime.Now, "", "@home") { new MockTaskResponsePart(12) }
                    }
                });

            TaskList smartList = Rtm.TaskLists[1];
            Assert.That(smartList.Tasks, Has.Count(1));

            Task newTask = new Task("Sort socks");
            smartList.AddTask(newTask);

            Assert.That(smartList.Tasks, Has.Count(1));
            smartList.IsFrozen = true;
            Assert.AreNotSame(newTask, smartList.Tasks[0]);
            Assert.AreSame(Rtm.TaskLists[0], newTask.Parent);
        }
    }
}
